﻿/// <reference name="MicrosoftAjax.js" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewBoundColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewButtonColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewCheckBoxColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewCommandColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewDropDownListColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewHyperLinkColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewImageColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewRadioButtonColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.GridView.Columns.GridViewTemplateColumn.js" assembly="AjaxDataControls" />
/// <reference name="AjaxDataControls.Common.Common.js" assembly="AjaxDataControls" />

Type.registerNamespace('AjaxDataControls');

$ADC.GridViewBaseColumn = function()
{
	/// <summary>
	/// The base class which represent a column of GridView Control.
	/// </summary>

	this._columnID = 0;
	this._controlStyle = null;
	this._headerStyle = null;
	this._headerText = '';
	this._sortField = '';
	this._allowDragAndDrop = true;
	this._visible = true;
	this._itemStyle = null;

	this._footerStyle = null;
	this._footerText = '';

	this._headerContainer = null;
	this._footerContainer = null;

	this._sortLink = null;
	this._sortHandler = null;

	this._owner = null;

	this._mouseDownHandler;
	this._isDraggingEnabled = false;

	$ADC.GridViewBaseColumn.initializeBase(this);
}

$ADC.GridViewBaseColumn.prototype =
{
    get_columnID: function()
    {
        /// <value type="Number" integer="true">
        /// The ID of the column which is used to uniquely identify the column among the other columns in the GridView Control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._columnID;
    },

    set_columnID: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Number}]);
        if (e) throw e;

        if (this._columnID != value)
        {
            this._columnID = value;
            this.raisePropertyChanged('columnID');
        }
    },

    get_controlStyle: function()
    {
        /// <value type="AjaxDataControls.Style" mayBeNull="true">
        /// The style of the controls contained by the column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._controlStyle;
    },

    set_controlStyle: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.Style}]);
        if (e) throw e;

        if (this._controlStyle != value)
        {
            this._controlStyle = value;
            this.raisePropertyChanged('controlStyle');
        }
    },

    get_headerStyle: function()
    {
        /// <value type="AjaxDataControls.TableItemStyle" mayBeNull="true">
        /// The style applied to header within this colum.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._headerStyle;
    },

    set_headerStyle: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._headerStyle != value)
        {
            this._headerStyle = value;
            this.raisePropertyChanged('headerStyle');
        }
    },

    get_headerText: function()
    {
        /// <value type="String">
        /// Use the HeaderText property to identify a field in a data control with a friendly name. The most common application of the HeaderText property is to provide meaningful column names for data-bound fields in a GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._headerText;
    },

    set_headerText: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._headerText != value)
        {
            this._headerText = value;
            this.raisePropertyChanged('headerText');
        }
    },

    get_sortField: function()
    {
        /// <value type="String">
        /// The sort field in the data source that is used by a data source control to sort data.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._sortField;
    },

    set_sortField: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._sortField != value)
        {
            this._sortField = value;
            this.raisePropertyChanged('sortField');
        }
    },

    get_allowDragAndDrop: function()
    {
        /// <value type="Boolean">
        /// Whether to allow drag and drop of this column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._allowDragAndDrop;
    },

    set_allowDragAndDrop: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._allowDragAndDrop != value)
        {
            this._allowDragAndDrop = value;
            this.raisePropertyChanged('allowDragAndDrop');
        }
    },

    get_visible: function()
    {
        /// <value type="Boolean">
        /// Whether the column is visible or not.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._visible;
    },

    set_visible: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._visible != value)
        {
            this._visible = value;
            this.raisePropertyChanged('visible');
        }
    },

    get_itemStyle: function()
    {
        /// <value type="AjaxDataControls.TableItemStyle" mayBeNull="true">
        /// The style of any text-based content displayed by the column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._itemStyle;
    },

    set_itemStyle: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._itemStyle != value)
        {
            this._itemStyle = value;
            this.raisePropertyChanged('itemStyle');
        }
    },

    get_footerStyle: function()
    {
        /// <value type="AjaxDataControls.TableItemStyle" mayBeNull="true">
        /// The style applied to footer within this column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._footerStyle;
    },

    set_footerStyle: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._footerStyle != value)
        {
            this._footerStyle = value;
            this.raisePropertyChanged('footerStyle');
        }
    },

    get_footerText: function()
    {
        /// <value type="String">
        /// The text within the footer of this column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._footerText;
    },

    set_footerText: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._footerText != value)
        {
            this._footerText = value;
            this.raisePropertyChanged('footerText');
        }
    },

    get_owner: function()
    {
        /// <value type="AjaxDataControls.GridView">
        /// The GridView which owns the column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._owner;
    },

    set_owner: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.GridView}]);
        if (e) throw e;

        if (this._owner != value)
        {
            this._owner = value;
        }
    },

    get_headerContainer: function()
    {
        /// <value domElement="true">
        /// The header container cell(th) of this column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._headerContainer;
    },

    set_headerContainer: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Object}]);
        if (e) throw e;

        if (this._headerContainer != value)
        {
            this._headerContainer = value;

            if (this._isDragAndDropAllowed())
            {
                this._mouseDownHandler = $ADC.Util.addDelegateEventHandler(this._headerContainer, 'mousedown', this, this._onMouseDown);

                var id = $ADC.Util.getRandomId();
                this.get_headerContainer().id = id;

                $ADC.UI.DragDropManager.registerDropTarget(this, id);
                if (this._isDragAndDropAllowed)
                {
                    $ADC.UI.DragDropManager.registerDragSource(this, id);
                }
            }
        }
    },

    get_footerContainer: function()
    {
        /// <value domElement="true">
        /// The footer container cell(td) of this column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._footerContainer;
    },

    set_footerContainer: function(value)
    {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Object}]);
        if (e) throw e;

        if (this._footerContainer != value)
        {
            this._footerContainer = value;
        }
    },

    initialize: function()
    {
        /// <summary>
        /// Initialize the column.
        /// </summary>

        $ADC.GridViewBaseColumn.callBaseMethod(this, 'initialize');
    },

    dispose: function()
    {
        /// <summary>
        /// Dispose the column.
        /// </summary>

        this.releaseResource();

        delete this._owner;
        delete this._headerContainer;
        delete this._footerContainer;

        delete this._mouseDownHandler;

        delete this._sortLink;
        delete this._sortHandler;

        delete this._controlStyle;
        delete this._headerStyle;
        delete this._itemStyle;
        delete this._footerStyle;

        $ADC.GridViewBaseColumn.callBaseMethod(this, 'dispose');
    },

    renderHeader: function(row)
    {
        /// <summary>
        /// Draws the header section in the previously specified header container. You will only override this method if you
        /// want to develop custom colum which requires extra logic. Other than this you do not have to call this method in your code.
        /// </summary>
        /// <param name="row" type="AjaxDataControls.GridViewRow">
        /// The GridViewRow which is passed to render the header that item type is set to <b>AjaxDataControls.GridViewRowType.Header</b>.
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'row', type: $ADC.GridViewRow}]);
        if (e) throw e;

        var owner = this.get_owner();
        var container = this.get_headerContainer();

        if (owner == null)
        {
            throw Error.invalidOperation('Owner must be set before calling this method.');
        }

        if (container == null)
        {
            throw Error.invalidOperation('Header container must be set before calling this method.');
        }

        var headerText = this.get_headerText();

        if (!$ADC.Util.isEmptyString(headerText))
        {
            var sortField = this.get_sortField();

            if (!$ADC.Util.isEmptyString(sortField))
            {
                this._sortLink = document.createElement('a');
                this._sortLink.appendChild(document.createTextNode(headerText));
                this._sortLink.href = 'javascript:void(0)';
                container.appendChild(this._sortLink);

                var sortColumn = owner.get_sortColumn();
                var sortOrder = $ADC.GridViewSortOrder.Ascending;

                if (sortColumn == sortField)
                {
                    var sortImageUrl = '';

                    if (owner.get_sortOrder() == $ADC.GridViewSortOrder.Ascending)
                    {
                        sortOrder = $ADC.GridViewSortOrder.Descending;
                        sortImageUrl = owner.get_sortOrderAscendingImageUrl();
                    }
                    else
                    {
                        sortImageUrl = owner.get_sortOrderDescendingImageUrl();
                    }

                    if (!$ADC.Util.isEmptyString(sortImageUrl))
                    {
                        var img = document.createElement('img');
                        img.setAttribute('src', sortImageUrl);
                        img.setAttribute('alt', '');
                        container.appendChild(img);
                    }
                }

                //Create a callback so that we can pass the sortColumn name and direction
                this._sortHandler = $ADC.Util.addCallbackEventHandler(this._sortLink, 'click', owner._raiseSort, { sender: owner, sortColumn: sortField, sortOrder: sortOrder });
            }
            else
            {
                if ($ADC.Util.isEmptyString(headerText))
                {
                    headerText = ' ';
                }

                container.appendChild(document.createTextNode(headerText));
            }
        }
        else
        {
            if ($ADC.Util.isEmptyString(headerText))
            {
                headerText = ' ';
            }

            container.appendChild(document.createTextNode(headerText));
        }

        if (this.get_headerStyle() != null)
        {
            this.get_headerStyle().apply(container);
        }

        if (this._isDragAndDropAllowed())
        {
            container.style.cursor = 'move';
            container.style.zIndex = '9999';
        }
    },

    renderData: function(dataRow, row, container)
    {
        /// <summary>
        /// Abstract method. The Derived column needs to override it. You do not have to call this method in you code.
        /// </summary>
        /// <param name="dataRow" type="Object">
        /// The item of the GridView dataSource.
        /// </param>
        /// <param name="row" type="AjaxDataControls.GridViewRow">
        /// The GridViewRow which is passed to render the column data cell.
        /// </param>
        /// <param name="container" domElement="true">
        /// The container cell(td) to render the data of this column.
        /// </param>

        throw Error.notImplemented();
    },

    renderFooter: function(row)
    {
        /// <summary>
        /// Draws the footer section in the previously specified footer container. You will only override this method if you
        /// want to develop custom colum which requires extra logic. Other than this you do not have to call this method in your code.
        /// </summary>
        /// <param name="row" type="AjaxDataControls.GridViewRow">
        /// The GridViewRow which is passed to render the footer that item type is set to <b>AjaxDataControls.GridViewRowType.Footer</b>.
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'row', type: $ADC.GridViewRow}]);
        if (e) throw e;

        var container = this.get_footerContainer();

        if (container == null)
        {
            throw Error.invalidOperation('Footer container must be set before calling this method.');
        }

        var footerText = this.get_footerText();

        if (!$ADC.Util.isEmptyString(footerText))
        {
            container.appendChild(document.createTextNode(footerText));
        }

        if (this.get_footerStyle() != null)
        {
            this.get_footerStyle().apply(container);
        }
    },

    releaseResource: function()
    {
        /// <summary>
        /// Releases all resources which are associated with this column.
        /// </summary>

        if (this._isDragAndDropAllowed())
        {
            if (this._headerContainer != null)
            {
                $removeHandler(this._headerContainer, 'mousedown', this._mouseDownHandler);
                $ADC.UI.DragDropManager.unregisterDropTarget(this);
            }

            if (this._visualClue != null)
            {
                document.getElementsByTagName('body')[0].removeChild(this._visualClue);
            }
        }

        if ((this._sortLink != null) && (this._sortHandler != null))
        {
            $removeHandler(this._sortLink, 'click', this._sortHandler);
        }
    },

    onDragStart: function()
    {
        /// <summary>
        /// Called when the drag started.
        /// </summary>

        this._owner._raiseColumnDragStart(this);
    },

    onDrag: function()
    {
        /// <summary>
        /// Called repeatedly when the while dragging. This method is empty or does not do anything.
        /// </summary>
    },

    onDragEnd: function()
    {
        // No need to remove the dragged element. 
        // jQuery takes care of this on its own.
    },

    drop: function(draggingColumn, rebind)
    {
        /// <summary>
        /// Called the when the column is dropped.
        /// </summary>
        /// <param name="draggingColumn" type="Object">
        /// The drag data which is the column itself.
        /// </param>

        var columns = this._owner.get_columns();
        var oldIndex = Array.indexOf(columns, draggingColumn);
        var newIndex = Array.indexOf(columns, this);

        var tds;
        var td;
        var maxIndex = 0;

        var trHeader = this._owner._headerRow.get_container();

        // We need to subtract 1, because jQuery adds the dragged element to the row. 
        // The dragged element is removed once the dropping procedure has finished 
        // automatically by jQuery.
        maxIndex = trHeader.childNodes.length - 1;

        //Now insert the column in proper order

        //First put the header
        tds = trHeader.childNodes;
        td = trHeader.removeChild(tds[oldIndex]);

        if ((newIndex >= maxIndex) || (newIndex + 1 >= maxIndex))
        {
            trHeader.appendChild(td);
        }
        else
        {
            trHeader.insertBefore(td, tds[newIndex]);
        }

        //Now the Datarows
        var length = this._owner._rows.length;
        var tr;

        for (var i = 0; i < length; i++)
        {
            tr = this._owner._rows[i].get_container();
            tds = tr.childNodes;
            td = tr.removeChild(tds[oldIndex]);

            if ((newIndex >= maxIndex) || (newIndex + 1 >= maxIndex))
            {
                tr.appendChild(td);
            }
            else
            {
                tr.insertBefore(td, tds[newIndex]);
            }
        }

        //Now the footer
        var trFooter = this._owner._footerRow.get_container();
        maxIndex = trFooter.childNodes.length

        if (maxIndex > 0)
        {
            tds = trFooter.childNodes;
            td = trFooter.removeChild(tds[oldIndex]);

            if ((newIndex >= maxIndex) || (newIndex + 1 >= maxIndex))
            {
                trFooter.appendChild(td);
            }
            else
            {
                trFooter.insertBefore(td, tds[newIndex]);
            }
        }

        //Now we have to modify the column collection so that
        //it can presist the order in future dataBind method
        var column = columns[oldIndex]; //Get the target column

        if (Array.remove(columns, column)) // Now Remove it from the Old index
        {
            Array.insert(columns, newIndex, column); // And insert it in new index
        }

        this._owner._raiseColumnDropped(draggingColumn, oldIndex, newIndex);

        if (typeof rebind != "undefined")
        {
            this._owner.set_groupField("");
            this._owner.set_sortColumn("");
            this._owner.dataBind();
        }
    },

    onDragEnterTarget: function(draggingColumn)
    {

    },

    onDragLeaveTarget: function(draggingColumn)
    {

    },

    onDragInTarget: function(draggingItem)
    {

    },

    _onMouseDown: function(e)
    {
        if (e.target == this._headerContainer)
        {
            window._event = e;
            e.preventDefault();
        }
    },

    _isDragAndDropAllowed: function()
    {
        var allowed = this.get_allowDragAndDrop();

        if (allowed)
        {
            allowed = $ADC.Util.hasDragNDropSupport();
        }

        return allowed;
    },

    _copyAttributes: function(sourceNode, targetNode)
    {
        if (Sys.Browser.agent == Sys.Browser.InternetExplorer)
        {
            targetNode.mergeAttributes(sourceNode); //Only IE supports it
        }
        else
        {
            var attributes = sourceNode.attributes;

            if ((attributes != null) && (attributes.length > 0))
            {
                var length = attributes.length;

                for (var i = 0; i < length; i++)
                {
                    targetNode.setAttribute(attributes[i].nodeName, attributes[i].nodeValue);
                }
            }
        }
    }
}

$ADC.GridViewBaseColumn.registerClass('AjaxDataControls.GridViewBaseColumn', Sys.Component);

$ADC.GridViewColumnButtonType = function()
{
	/// <summary>
	/// Specifies the different types of buttons that can be rendered in a GridView control.
	/// </summary>
	/// <field name="Button" type="Number" integer="true" static="true">A command button.</field>
	/// <field name="Image" type="Number" integer="true" static="true">A button that displays an image.</field>
	/// <field name="Link" type="Number" integer="true" static="true">A hyperlink-style button.</field>

	throw Error.notImplemented();
}

$ADC.GridViewColumnButtonType.prototype =
{
	Button: 0,
	Image: 1,
	Link: 2
}

$ADC.GridViewColumnButtonType.registerEnum('AjaxDataControls.GridViewColumnButtonType');

$ADC.GridViewColumnSelectButtonType = function()
{
	/// <summary>
	/// Specifies the different types of buttons that can be rendered in a GridView control.
	/// </summary>
	/// <field name="Button" type="Number" integer="true" static="true">A command button.</field>
	/// <field name="Image" type="Number" integer="true" static="true">A button that displays an image.</field>
	/// <field name="Link" type="Number" integer="true" static="true">A hyperlink-style button.</field>
	/// <field name="CheckBox" type="Number" integer="true" static="true">A checkbox-style button.</field>

	throw Error.notImplemented();
}

$ADC.GridViewColumnSelectButtonType.prototype =
{
	Button: 0,
	Image: 1,
	Link: 2,
	CheckBox: 3
}

$ADC.GridViewColumnSelectButtonType.registerEnum('AjaxDataControls.GridViewColumnSelectButtonType');

$ADC.GridViewColumnDragStartEventArgs = function(column)
{
	/// <summary>
	/// Event arguments used for the GridView column drag start event.
	/// </summary>
	/// <param name="column" type="AjaxDataControls.GridViewBaseColumn">
	/// The Column object.
	/// </param>

	var e = Function._validateParams(arguments, [{ name: 'column', type: $ADC.GridViewBaseColumn}]);
	if (e) throw e;

	this._column = column;
	$ADC.GridViewColumnDragStartEventArgs.initializeBase(this);
}

$ADC.GridViewColumnDragStartEventArgs.prototype =
{
	get_column: function()
	{
		/// <value type="AjaxDataControls.GridViewBaseColumn">
		/// The associated Column object.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._column;
	}
}

$ADC.GridViewColumnDragStartEventArgs.registerClass('AjaxDataControls.GridViewColumnDragStartEventArgs', Sys.EventArgs);


$ADC.GridViewColumnDroppedEventArgs = function(column, oldIndex, newIndex)
{
	/// <summary>
	/// Event arguments used for the GridView column dropped event.
	/// </summary>
	/// <param name="column" type="AjaxDataControls.GridViewBaseColumn">
	/// The Column object which is dropped.
	/// </param>
	/// <param name="oldIndex" type="Number" integer="true">
	/// The old index of the column.
	/// </param>
	/// <param name="newIndex" type="Number" integer="true">
	/// The new index of the column.
	/// </param>

	var e = Function._validateParams(arguments, [{ name: 'column', type: $ADC.GridViewBaseColumn }, { name: 'oldIndex', type: Number }, { name: 'newIndex', type: Number}]);
	if (e) throw e;

	this._column = column;
	this._oldIndex = oldIndex;
	this._newIndex = newIndex;

	$ADC.GridViewColumnDroppedEventArgs.initializeBase(this);
}

$ADC.GridViewColumnDroppedEventArgs.prototype =
{
	get_column: function()
	{
		/// <value type="AjaxDataControls.GridViewBaseColumn">
		/// The associated Column object.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._column;
	},

	get_oldIndex: function()
	{
		/// <value type="Number" integer="true">
		/// The old index of the colum.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._oldIndex;
	},

	get_newIndex: function()
	{
		/// <value type="Number" integer="true">
		/// The new index of the colum.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._newIndex;
	}
}

$ADC.GridViewColumnDroppedEventArgs.registerClass('AjaxDataControls.GridViewColumnDroppedEventArgs', Sys.EventArgs);


$ADC.GridViewSortOrder = function()
{
	/// <summary>
	/// Specifies the direction in which to sort the GridView Rows.
	/// </summary>
	/// <field name="None" type="Number" integer="true" static="true">Do not sort</field>
	/// <field name="Ascending" type="Number" integer="true" static="true">Sort from smallest to largest. For example, from A to Z.</field>
	/// <field name="Descending" type="Number" integer="true" static="true">Sort from largest to smallest. For example, from Z to A.</field>

	throw Error.notImplemented();
}

$ADC.GridViewSortOrder.prototype =
{
	None: 0,
	Ascending: 1,
	Descending: 2
}

$ADC.GridViewSortOrder.registerEnum('AjaxDataControls.GridViewSortOrder');


$ADC.GridViewSortCommandEventArgs = function(sortColumn, sortOrder)
{
	/// <summary>
	/// Event arguments used for the GridView sort command event.
	/// </summary>
	/// <param name="sortColumn" type="String">
	/// The name of the sort column that is associated with this column.
	/// </param>
	/// <param name="sortOrder" type="AjaxDataControls.GridViewSortOrder">
	/// The order to sort.
	/// </param>

	var e = Function._validateParams(arguments, [{ name: 'sortColumn', type: String }, { name: 'sortOrder', type: $ADC.GridViewSortOrder}]);
	if (e) throw e;

	this._sortColumn = sortColumn;
	this._sortOrder = sortOrder;

	$ADC.GridViewSortCommandEventArgs.initializeBase(this);
}

$ADC.GridViewSortCommandEventArgs.prototype =
{
	get_sortColumn: function()
	{
		/// <value type="String">
		/// The sort column.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._sortColumn;
	},

	get_sortOrder: function()
	{
		/// <value type="AjaxDataControls.GridViewSortOrder">
		/// The order to sort.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._sortOrder;
	}
}

$ADC.GridViewSortCommandEventArgs.registerClass('AjaxDataControls.GridViewSortCommandEventArgs', Sys.EventArgs);


$ADC.GridViewRowType = function()
{
	/// <summary>
	/// Specifies the type of an row in a GridView control.
	/// </summary>
	/// <field name="NotSet" type="Number" integer="true" static="true">Not set. Used internally.</field>
	/// <field name="Header" type="Number" integer="true" static="true">A header for the GridView control. It is not data-bound.</field>
	/// <field name="Footer" type="Number" integer="true" static="true">A footer for the GridView control. It is not data-bound. </field>
	/// <field name="Row" type="Number" integer="true" static="true">A row in the GridView control. It is data-bound.</field>
	/// <field name="AlternatingRow" type="Number" integer="true" static="true">An alternating row (zero-based even-indexed). It is data-bound.</field>
	/// <field name="SelectedRow" type="Number" integer="true" static="true">A selected row in the GridView control. It is data-bound.</field>
	/// <field name="EditRow" type="Number" integer="true" static="true">A row in a GridView control currently in edit mode. It is data-bound.</field>
	/// <field name="InsertRow" type="Number" integer="true" static="true">A row in a GridView control currently in insert mode. It is data-bound.</field>

	throw Error.notImplemented();
}

$ADC.GridViewRowType.prototype =
{
	NotSet: 0,
	Header: 1,
	Footer: 2,
	Row: 3,
	AlternatingRow: 4,
	SelectedRow: 5,
	EditRow: 6,
	InsertRow: 7
}

$ADC.GridViewRowType.registerEnum('AjaxDataControls.GridViewRowType');


$ADC.GridViewRow = function(namingContainer, container, rowIndex, rowType, dataItem, gridView)
{
	/// <summary>
	/// Represents an individual row in a GridView Control.
	/// </summary>
	/// <param name="namingContainer" type="string">
	/// The naming container, which creates a unique namespace for differentiating between controls with the same Control.ID property value.
	/// </param>
	/// <param name="container" domElement="true">
	/// The container html table row (tr) where the row will be rendered.
	/// </param>
	/// <param name="rowIndex" type="Number" integer="true">
	/// The Index of the item.
	/// </param>
	/// <param name="rowType" type="AjaxDataControls.GridViewRowType">
	/// The Type of the row.
	/// </param>
	/// <param name="dataItem" type="Object" mayBeNull="true">
	/// The associate data with this row of the data source of the GridView that the row belongs.
	/// </param>

	var e = Function._validateParams(arguments, [{ name: 'namingContainer', type: String }, { name: 'container', type: Object }, { name: 'rowIndex', type: Number }, { name: 'rowType', type: $ADC.GridViewRowType }, { name: 'dataItem', mayBeNull: true }, { name: 'gridView', mayBeNull: true }]);
	if (e) throw e;

	this._namingContainer = namingContainer;
	this._container = container;
	this._rowIndex = rowIndex;
	this._rowType = rowType;
	this._dataItem = dataItem;
	this._controls = new Array();
	this._owner = gridView;
}

$ADC.GridViewRow.prototype =
{
	get_isSelected: function()
	{
		/// <value type="Boolean">
		/// Whether to GridViewRow must be selected.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._isSelected;
	},

	set_isSelected: function(value)
	{
		var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
		if (e) throw e;

		this._isSelected = value;
	},

	get_container: function()
	{
		/// <value domElement="true">
		/// The container table row (tr).
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._container;
	},

	get_rowIndex: function()
	{
		/// <value type="Number" integer="true">
		/// The container table row (tr).
		/// The index of the row in the GridView control from the Rows collection of the control.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._rowIndex;
	},

	get_rowType: function()
	{
		/// <value type="AjaxDataControls.GridViewRowType">
		/// The Type of the row.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._rowType;
	},

	set_rowType: function(value)
	{
		var e = Function._validateParams(arguments, [{ name: 'value', type: AjaxDataControls.GridViewRowType}]);
		if (e) throw e;

		this._rowType = value;
	},

	get_dataItem: function()
	{
		/// <value type="Object" mayBeNull="true">
		/// The data of the datasource which is associated with this row.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._dataItem;
	},

	get_isDataRowType: function()
	{
		/// <value type="Boolean">
		/// Checks if the row is a data row. Use it when you want to exclude the non data rows like header, footer.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		var rowType = this.get_rowType();

		return (
                    (rowType == $ADC.GridViewRowType.Row) ||
                    (rowType == $ADC.GridViewRowType.AlternatingRow) ||
                    (rowType == $ADC.GridViewRowType.SelectedRow) ||
                    (rowType == $ADC.GridViewRowType.InsertRow) ||
                    (rowType == $ADC.GridViewRowType.EditRow)
                );
	},

	dispose: function()
	{
		/// <summary>
		/// Dispose the row.
		/// </summary>

		if (arguments.length !== 0) throw Error.parameterCount();

		for (var i = this._controls.length - 1; i > -1; i--)
		{
			delete this._controls[i];
		}

		Array.clear(this._controls);
		delete this._controls;

		delete this._container;
	},

	getCellByColumnDataField: function(dataField)
	{
		var e = Function._validateParams(arguments, [{ name: 'dataField', type: String}]);
		if (e) throw e;

		var element = this.get_container().cells[this._owner.getColumnIndexByDataField(dataField)];
		if ((element.childNodes) && (element.childNodes.length > 0))
		{
			element = element.childNodes[0];
		}
		return element;
	},

	findControl: function(controlId)
	{
		/// <summary>
		/// Finds the specified control from the row control collection.
		/// </summary>
		/// <param name="controlId" type="String">
		/// The control ID without the naming container.
		/// </param>
		/// <returns domElement="true" mayBeNull="true">
		/// Returns the dom element from the control collection.
		/// </returns>

		var e = Function._validateParams(arguments, [{ name: "controlId", type: String}]);
		if (e) throw e;

		var targetId = (this._namingContainer + '$' + controlId);
		var index = Array.indexOf(this._controls, targetId);

		if (index > -1)
		{
			return $get(targetId);
		}

		return null;
	},

	_addControl: function(childControl)
	{
		if ((childControl.id != null) && (childControl.id.length > 0))
		{
			var targetId = (this._namingContainer + '$' + childControl.id);

			if (Array.contains(this._controls, targetId))
			{
				throw Error.invalidOperation('Control of the same id already exists.');
			}

			childControl.id = targetId;
			Array.add(this._controls, childControl.id);
		}
	}
}

$ADC.GridViewRow.registerClass('AjaxDataControls.GridViewRow', null, Sys.IDisposable);


$ADC.GridViewRowEventArgs = function(row)
{
	/// <summary>
	/// Event arguments used when the GridView row is created or databound.
	/// </summary>
	/// <param name="item" type="AjaxDataControls.GridViewRow">
	/// The associated GridView row.
	/// </param>

	var e = Function._validateParams(arguments, [{ name: 'row', type: $ADC.GridViewRow}]);
	if (e) throw e;

	$ADC.GridViewRowEventArgs.initializeBase(this);
	this._row = row;
}

$ADC.GridViewRowEventArgs.prototype =
{
	get_row: function()
	{
		/// <value type="AjaxDataControls.GridViewRow">
		/// The GridView row associated with this event.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._row;
	}
}

$ADC.GridViewRowEventArgs.registerClass('AjaxDataControls.GridViewRowEventArgs', Sys.EventArgs);


$ADC.GridViewCommandEventArgs = function(commandName, commandArgument, commandSource, row)
{
	/// <summary>
	/// Event arguments used for the GridView command event.
	/// </summary>
	/// <param name="commandName" type="String">
	/// The associated command name.
	/// </param>
	/// <param name="commandArgument" type="Object">
	/// The associated command argument.
	/// </param>
	/// <param name="commandSource" domElement="true">
	/// The associated command source, usually the dom button which fires the command event.
	/// </param>
	/// <param name="item" type="AjaxDataControls.GridViewRow">
	/// The associated GridView row.
	/// </param>

	var e = Function._validateParams(arguments, [{ name: 'commandName', type: String }, { name: 'commandArgument' }, { name: 'commandSource', type: Object }, { name: 'row', type: $ADC.GridViewRow}]);
	if (e) throw e;

	$ADC.GridViewCommandEventArgs.initializeBase(this);
	this._commandName = commandName;
	this._commandArgument = commandArgument;
	this._commandSource = commandSource;
	this._row = row;
}

$ADC.GridViewCommandEventArgs.prototype =
{
	get_commandName: function()
	{
		/// <value type="String">
		/// The associated command name.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._commandName;
	},

	get_commandArgument: function()
	{
		/// <value type="Object">
		/// The associated command argument.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._commandArgument;
	},

	get_commandSource: function()
	{
		/// <value domElement="true">
		/// The associated command source, usually the dom button which fires the command event.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._commandSource;
	},

	get_row: function()
	{
		/// <value type="AjaxDataControls.GridViewRow">
		/// The associated GridView row.
		/// </value>

		if (arguments.length !== 0) throw Error.parameterCount();

		return this._row;
	}
}

$ADC.GridViewCommandEventArgs.registerClass('AjaxDataControls.GridViewCommandEventArgs', Sys.EventArgs);


$ADC.GridView = function(element)
{
	/// <summary>
	/// Displays the values of a data source in a table where each column represents a column and each row represents a record. The GridView control allows you to select, sort, and edit these items.
	/// </summary>
	/// <param name="element" domElement="true">
	/// The dom element where the GridView will be rendered.
	/// </param>

	this.SelectCommandName = 'select';
	this.EditCommandName = 'edit';
	this.InsertCommandName = 'insert';
	this.UpdateCommandName = 'update';
	this.CancelCommandName = 'cancel';
	this.DeleteCommandName = 'delete';

	this._showHeader = true;
	this._showFooter = false;

	this._autoGenerateDeleteButton = false;
	this._autoGenerateEditButton = false;
	this._autoGenerateInsertButton = false;
	this._autoGenerateSelectButton = false;

	this._emptyDataTemplate = '';
	this._emptyDataText = '';

	this._sortColumn = '';
	this._sortOrder = $ADC.GridViewSortOrder.Ascending;

	this._sortOrderAscendingImageUrl = '';
	this._sortOrderDescendingImageUrl = '';

	this._headerStyle = null;
	this._groupingStyle = null;
	this._rowStyle = null;
	this._alternatingRowStyle = null;
	this._footerStyle = null;
	this._selectedRowStyle = null;
	this._editRowStyle = null;
	this._insertRowStyle = null;
	this._emptyDataRowStyle = null;

	this._dataKeyName = null;
	this._dataKeys = new Array();

	this._groupField = null;
	this._groupFieldValues = new Array();

	this._columns = null;
	this._dataSource = null;
	this._hasBinded = false;
	this._rows = new Array();

	this._headerRow = null;
	this._footerRow = null;

	this._selectedIndexes = new Array(); 
	this._lastSelectedIndex = 0;	
	this._editIndex = -1;

	this._insertImageUrl = '';
	this._insertText = 'Insert';
	this._insertCancelImageUrl = '';
	this._insertCancelText = 'Cancel';
	this._showInsertCancelButton = false;
										 
	this._dragOpacity = 70;

	this._animate = true
	this._animationDuration = 0.2;
	this._animationFps = 20;
	this._animation = null;

	this._profileLoadedHandler = null;
	this._profileSavedHandler = null;

	$ADC.GridView.initializeBase(this, [element]);
}

$ADC.GridView.prototype =
{
    get_border: function() {
        /// <value type="Number" integer="true">
        /// The border of the control in pixels.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this.get_element().border;
    },

    set_border: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Number}]);
        if (e) throw e;

        if (this.get_element().border != value) {
            this.get_element().border = value;
            this.raisePropertyChanged('border');
        }
    },

    get_cellPadding: function() {
        /// <value type="Number" integer="true">
        /// The amount of space (in pixels) between the contents of a cell and the cell's border.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this.get_element().cellPadding;
    },

    set_cellPadding: function(value) {
        /// <value type="Number" integer="true">
        /// The amount of space (in pixels) between cells.
        /// </value>

        var e = Function._validateParams(arguments, [{ name: 'value', type: Number}]);
        if (e) throw e;

        if (this.get_element().cellPadding != value) {
            this.get_element().cellPadding = value;
            this.raisePropertyChanged('cellPadding');
        }
    },

    get_cellSpacing: function() {
        /// <value type="Number" integer="true">
        /// The amount of space (in pixels) between cells.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this.get_element().cellSpacing;
    },

    set_cellSpacing: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Number}]);
        if (e) throw e;

        if (this.get_element().cellSpacing != value) {
            this.get_element().cellSpacing = value;
            this.raisePropertyChanged('cellSpacing');
        }
    },

    get_cssClass: function() {
        /// <value type="String">
        /// The associated css class name for this control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this.get_element().className;
    },

    set_cssClass: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        var target = this.get_element();

        if (!Sys.UI.DomElement.containsCssClass(target, value)) {
            Sys.UI.DomElement.addCssClass(target, value);
            this.raisePropertyChanged('cssClass');
        }
    },

    get_showHeader: function() {
        /// <value type="Boolean">
        /// Whether to show the GridView header.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._showHeader;
    },

    set_showHeader: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._showHeader != value) {
            this._showHeader = value;
            this.raisePropertyChanged('showHeader');
        }
    },

    get_showFooter: function() {
        /// <value type="Boolean">
        /// Whether to show the GridView footer.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._showFooter;
    },

    set_showFooter: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._showFooter != value) {
            this._showFooter = value;
            this.raisePropertyChanged('showFooter');
        }
    },

    get_autoGenerateDeleteButton: function() {
        /// <value type="Boolean">
        /// Whether the delete button is generated automatically at runtime.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._autoGenerateDeleteButton;
    },

    set_autoGenerateDeleteButton: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._autoGenerateDeleteButton != value) {
            this._autoGenerateDeleteButton = value;
            this.raisePropertyChanged('autoGenerateDeleteButton');
        }
    },
    get_autoGenerateInsertButton: function() {
        /// <value type="Boolean">
        /// Whether the insert button is generated automatically at runtime.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._autoGenerateInsertButton;
    },

    set_autoGenerateInsertButton: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._autoGenerateInsertButton != value) {
            this._autoGenerateInsertButton = value;
            this.raisePropertyChanged('autoGenerateInsertButton');
        }
    },

    /*   get_insertImageUrl : function()
    {
    /// <value type="String">
    /// Use this property to specify the image to display for the Edit button. This image can be in any file format (.jpg, .gif, .bmp, and so on), as long as the client's browser supports that format.
    /// </value>
    if (arguments.length !== 0) throw Error.parameterCount();

	return this._inertImageUrl;
    },

	set_insertImageUrl : function(value)
    {
    var e = Function._validateParams(arguments, [{name: 'value', type: String}]);
    if (e) throw e;

	if (this._inertImageUrl != value)
    {
    this._inertImageUrl = value;
    this.raisePropertyChanged('inertImageUrl');
    }
    },

	get_insertText : function()
    {
    /// <value type="String">
    /// Use this property to specify the text to display for the Edit button.
    /// </value>
    if (arguments.length !== 0) throw Error.parameterCount();

	return this._insertText;
    },

	set_insertText : function(value)
    {
    var e = Function._validateParams(arguments, [{name: 'value', type: String}]);
    if (e) throw e;

	if (this._insertText != value)
    {
    this._insertText = value;
    this.raisePropertyChanged('insertText');
    }
    },


	get_insertCancelImageUrl : function()
    {
    /// <value type="String">
    /// Use this property to specify the image to display for the Edit button. This image can be in any file format (.jpg, .gif, .bmp, and so on), as long as the client's browser supports that format.
    /// </value>
    if (arguments.length !== 0) throw Error.parameterCount();

	return this._inertCancelImageUrl;
    },

	set_insertCancelImageUrl : function(value)
    {
    var e = Function._validateParams(arguments, [{name: 'value', type: String}]);
    if (e) throw e;

	if (this._inertCancelImageUrl != value)
    {
    this._inertCancelImageUrl = value;
    this.raisePropertyChanged('inertCancelImageUrl');
    }
    },

	get_insertCancelText : function()
    {
    /// <value type="String">
    /// Use this property to specify the text to display for the Edit button.
    /// </value>
    if (arguments.length !== 0) throw Error.parameterCount();

	return this._insertCancelText;
    },

	set_insertCancelText : function(value)
    {
    var e = Function._validateParams(arguments, [{name: 'value', type: String}]);
    if (e) throw e;

	if (this._insertCancelText != value)
    {
    this._insertCancelText = value;
    this.raisePropertyChanged('insertCancelText');
    }
    },

	get_showInsertCancelButton : function()
    {
    /// <value type="Boolean">
    /// Whether the edit button is generated automatically at runtime.
    /// </value>

	if (arguments.length !== 0) throw Error.parameterCount();

	return this._showInsertCancelButton;
    },

	set_showInsertCancelButton : function(value)
    {
    var e = Function._validateParams(arguments, [{name: 'value', type: Boolean}]);
    if (e) throw e;

	if (this._showInsertCancelButton != value)
    {
    this._showInsertCancelButton = value;
    this.raisePropertyChanged('showInsertCancelButton');
    }
    },
    */
    get_autoGenerateEditButton: function() {
        /// <value type="Boolean">
        /// Whether the edit button is generated automatically at runtime.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._autoGenerateEditButton;
    },

    set_autoGenerateEditButton: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._autoGenerateEditButton != value) {
            this._autoGenerateEditButton = value;
            this.raisePropertyChanged('autoGenerateEditButton');
        }
    },

    get_autoGenerateSelectButton: function() {
        /// <value type="Boolean">
        /// Whether the select button is generated automatically at runtime.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._autoGenerateSelectButton;
    },

    set_autoGenerateSelectButton: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._autoGenerateSelectButton != value) {
            this._autoGenerateSelectButton = value;
            this.raisePropertyChanged('autoGenerateSelectButton');
        }
    },

    get_groupField: function() {
        /// <value type="String">
        /// The column used to sort the data source to which the GridView is binding.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._groupField;
    },

    set_groupField: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._groupField != value) {
            this._groupField = value;
            this.raisePropertyChanged('groupField');
        }
    },


    get_sortColumn: function() {
        /// <value type="String">
        /// The column used to sort the data source to which the GridView is binding.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._sortColumn;
    },

    set_sortColumn: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._sortColumn != value) {
            this._sortColumn = value;
            this.raisePropertyChanged('sortColumn');
        }
    },

    get_sortOrder: function() {
        /// <value type="AjaxDataControls.GridViewSortOrder">
        /// The order in which to sort the column.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._sortOrder;
    },

    set_sortOrder: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.GridViewSortOrder}]);
        if (e) throw e;

        if (this._sortOrder != value) {
            this._sortOrder = value;
            this.raisePropertyChanged('sortOrder');
        }
    },

    get_sortOrderAscendingImageUrl: function() {
        /// <value type="String">
        /// The image that will be shown to indicate the ascending order.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._sortOrderAscendingImageUrl;
    },

    set_sortOrderAscendingImageUrl: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._sortOrderAscendingImageUrl != value) {
            this._sortOrderAscendingImageUrl = value;
            this.raisePropertyChanged('sortOrderAscendingImageUrl');
        }
    },

    get_sortOrderDescendingImageUrl: function() {
        /// <value type="String">
        /// The image that will be shown to indicate the descending order.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._sortOrderDescendingImageUrl;
    },

    set_sortOrderDescendingImageUrl: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._sortOrderDescendingImageUrl != value) {
            this._sortOrderDescendingImageUrl = value;
            this.raisePropertyChanged('sortOrderDescendingImageUrl');
        }
    },

    get_headerStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The the style of the header row in a GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._headerStyle;
    },

    set_headerStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._headerStyle != value) {
            this._headerStyle = value;
            this.raisePropertyChanged('headerStyle');
        }
    },


    get_groupingStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The the style of the header row in a GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._groupingStyle;
    },

    set_groupingStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._groupingStyle != value) {
            this._groupingStyle = value;
            this.raisePropertyChanged('groupingStyle');
        }
    },

    get_rowStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The style to set the appearance of the data rows in a GridView control. 
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._rowStyle;
    },

    set_rowStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._rowStyle != value) {
            this._rowStyle = value;
            this.raisePropertyChanged('rowStyle');
        }
    },

    get_alternatingRowStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The style to set the appearance of the alternating data rows in a GridView control. 
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._alternatingRowStyle;
    },

    set_alternatingRowStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._alternatingRowStyle != value) {
            this._alternatingRowStyle = value;
            this.raisePropertyChanged('alternatingRowStyle');
        }
    },

    get_footerStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The the style of the footer row in a GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._footerStyle;
    },

    set_footerStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._footerStyle != value) {
            this._footerStyle = value;
            this.raisePropertyChanged('footerStyle');
        }
    },

    get_selectedRowStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The the style of the selected row in a GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._selectedRowStyle;
    },

    set_selectedRowStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._selectedRowStyle != value) {
            this._selectedRowStyle = value;
            this.raisePropertyChanged('selectedRowStyle');
        }
    },

    get_editRowStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The the style of the edit row in a GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._editRowStyle;
    },

    set_editRowStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._editRowStyle != value) {
            this._editRowStyle = value;
            this.raisePropertyChanged('editRowStyle');
        }
    },

    get_insertRowStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The the style of the edit row in a GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._insertRowStyle;
    },

    set_insertRowStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._insertRowStyle != value) {
            this._insertRowStyle = value;
            this.raisePropertyChanged('insertRowStyle');
        }
    },

    get_emptyDataRowStyle: function() {
        /// <value type="AjaxDataControls.TableItemStyle">
        /// The the style of the empty row in a GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._emptyDataRowStyle;
    },

    set_emptyDataRowStyle: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: $ADC.TableItemStyle}]);
        if (e) throw e;

        if (this._emptyDataRowStyle != value) {
            this._emptyDataRowStyle = value;
            this.raisePropertyChanged('emptyDataRowStyle');
        }
    },

    get_dragOpacity: function() {
        /// <value type="Number" integer="true">
        /// The opacity of the drag visual.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._dragOpacity;
    },

    set_dragOpacity: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Number}]);
        if (e) throw e;

        if ((value < 0) || (value > 10)) {
            throw Error.argument('value', 'Drag opacity must be 0-100.');
        }

        if (this._dragOpacity != value) {
            this._dragOpacity = value;
            this.raisePropertyChanged('dragOpacity');
        }
    },

    get_animate: function() {
        /// <value type="Boolean">
        /// Whether the control animate fade in effect when databinding is complete.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._animate;
    },

    set_animate: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Boolean}]);
        if (e) throw e;

        if (this._animate != value) {
            this._animate = value;
            this.raisePropertyChanged('animate');
        }
    },

    get_animationDuration: function() {
        /// <value type="Number">
        /// The animation duration in seconds.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._animationDuration;
    },

    set_animationDuration: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Number}]);
        if (e) throw e;

        if (this._animationDuration != value) {
            this._animationDuration = value;
            this.raisePropertyChanged('animationDuration');
        }
    },

    get_animationFps: function() {
        /// <value type="Number" integer="true">
        /// The animation frames per second.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._animationFps;
    },

    set_animationFps: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Number}]);
        if (e) throw e;

        if (this._animationFps != value) {
            this._animationFps = value;
            this.raisePropertyChanged('animationFps');
        }
    },

    get_dataKeyName: function() {
        /// <value type="String">
        /// The name of the field in the data source which is used to populate the dataKeys Property.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._dataKeyName;
    },

    set_dataKeyName: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._dataKeyName != value) {
            this._dataKeyName = value;
            this.raisePropertyChanged('dataKeyName');
        }
    },

    get_dataKeys: function() {
        /// <value type="Array" mayBeNull="true">
        /// Stores the key values of each record in a DataList control. This allows you to store the key field with a GridView control without displaying it in the control. This collection is automatically filled with the values from the field specified by the DataKeyName property.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._dataKeys;
    },

    get_columns: function() {
        /// <value type="Array" mayBeNull="true" elementType="AjaxDataControls.GridViewBaseColumn">
        /// The set of columns to be shown in the control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._columns;
    },

    set_columns: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Array, elementType: $ADC.GridViewBaseColumn, elementMayBeNull: false}]);
        if (e) throw e;

        if (this._columns != value) {
            this._columns = value;
            this.raisePropertyChanged('columns');
        }
    },

    get_selectedIndexes: function() {
        /// <value type="Array" elementType="Number" elementInteger="true">
        /// An array of selected indexes of the GridView Control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._selectedIndexes;
    },

    set_selectedIndexes: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Array, elementType: Number, elementInteger: true}]);
        if (e) throw e;

        Array.foreach(value, this.selectRow);
    },

    get_selectedRows: function() {
        /// <value type="Array" elementType="AjaxDataControls.GridViewRow">
        /// An array of selected rows of the GridView Control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        if (this._selectedIndexes < 0) return null;

        if (this._rows.length > 0) {
            var rows = new Array();
            var indexes = this.get_selectedIndexes();
            var length = indexes.length;
            for (var i = 0; i < length; i++) {
                Array.add(rows, this._rows[indexes[i]]);
            }
            return rows;
        }
    },

    get_selectedValues: function() {
        /// <value type="Object" mayBeNull="true">
        /// The values of the selected rows by using the dataKeyName.
        /// </value>
        if (arguments.length !== 0) throw Error.parameterCount();

        if ((this.get_dataSource() == null) || (this.get_dataSource().length == 0)) {
            return null;
        }

        var dataKeyName = this.get_dataKeyName();
        if ((dataKeyName == null) || (dataKeyName.length == 0)) {
            return null;
        }

        var indexes = this.get_selectedIndexes();
        var length = indexes.length;
        if (length > 0) {
            var values = new Array();
            for (var i = 0; i < length; i++) {
                Array.add(values, this._dataKeys[indexes[i]]);
            }
            return values;
        }

        return null;
    },

    get_editIndex: function() {
        /// <value type="Number" integer="true">
        /// The index of the currently editing row.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._editIndex;
    },

    set_editIndex: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Number}]);
        if (e) throw e;

        if (this._editIndex != value) {
            this._editIndex = value;
            this.raisePropertyChanged('editIndex');

            if (this._hasBinded) {
                this._internalDataBind(false);
            }
        }
    },

    get_editRow: function() {
        /// <value type="AjaxDataControls.GridViewRow" mayBeNull="true">
        /// The edit row of the GridView Control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        if (this._editIndex < 0) {
            return null;
        }

        if (this._rows.length > 0) {
            return this._rows[this._editIndex];
        }

        return null;
    },

    get_dataSource: function() {
        /// <value type="Array" mayBeNull="true">
        /// The data source that provides data for populating the GridView.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._dataSource;
    },

    set_dataSource: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Array, mayBeNull: true}]);
        if (e) throw e;

        if (this._dataSource != value) {
            this._dataSource = value;
            this._hasBinded = false;
            this.raisePropertyChanged('dataSource');
        }
    },

    get_headerRow: function() {
        /// <value type="AjaxDataControls.GridViewRow" mayBeNull="true">
        /// The header row of the GridView Control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._headerRow;
    },

    get_rows: function() {
        /// <value type="Array" mayBeNull="true" elementType="AjaxDataControls.GridViewRow">
        /// The collection of GridViewRow objects in the GridView control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._rows;
    },

    get_footerRow: function() {
        /// <value type="AjaxDataControls.GridViewRow" mayBeNull="true">
        /// The footer row of the GridView Control.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._footerRow;
    },

    get_emptyDataTemplate: function() {
        /// <value type="String" mayBeNull="true">
        /// The empty data row template which is used when a GridView control is bound to a data source that does not contain any records.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._emptyDataTemplate;
    },

    set_emptyDataTemplate: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._emptyDataTemplate != value) {
            this._emptyDataTemplate = value;
            this.raisePropertyChanged('emptyDataTemplate');
        }
    },

    get_emptyDataText: function() {
        /// <value type="String" mayBeNull="true">
        /// The text shown in the empty data row if no EmptyDataTemplate is defined.
        /// </value>

        if (arguments.length !== 0) throw Error.parameterCount();

        return this._emptyDataText;
    },

    set_emptyDataText: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: String}]);
        if (e) throw e;

        if (this._dataSource != value) {
            this._emptyDataText = value;
            this.raisePropertyChanged('emptyDataText');
        }
    },

    insertRows: function(value) {
        var e = Function._validateParams(arguments, [{ name: 'value', type: Array, mayBeNull: true}]);
        if (e) throw e;

        this._internalInsertRows(value);
    },

    initialize: function() {
        /// <summary>
        /// Initialize the control.
        /// </summary>

        $ADC.GridView.callBaseMethod(this, 'initialize');
    },

    dispose: function() {
        /// <summary>
        /// Dispose the control.
        /// </summary>

        if (this._profileLoadedHandler != null) {
            delete this._profileLoadedHandler;
        }

        if (this._profileLoadedHandler != null) {
            delete this._profileSavedHandler;
        }

        if (this._animation != null) {
            this._animation.dispose();
        }

        delete this._animation;

        if (this._headerRow != null) {
            this._headerRow.dispose();
        }

        delete this._headerRow;

        if (this._footerRow != null) {
            this._footerRow.dispose();
        }

        delete this._footerRow;

        this._cleanupRows();
        delete this._rows;

        Array.clear(this._dataKeys);
        delete this._dataKeys;

        if (this._columns != null) {
            Array.clear(this._columns);
        }

        delete this._columns;
        delete this._dataSource;
        delete this._headerStyle;
        delete this._rowStyle;
        delete this._groupingStyle;
        delete this._alternatingRowStyle;
        delete this._footerStyle;
        delete this._selectedRowStyle;
        delete this._editRowStyle;
        delete this._insertRowStyle;
        delete this._emptyDataRowStyle;

        $ADC.GridView.callBaseMethod(this, 'dispose');
    },

    dataBind: function() {
        /// <summary>
        /// Binds the data source to the DataList control.
        /// </summary>

        if (arguments.length !== 0) throw Error.parameterCount();
        this._internalDataBind(true);
    },

    getColumnIndexByColumnID: function(columnID) {
        /// <summary>
        /// Returns the Index of the specified columnID.
        /// </summary>
        /// <param name="columnID" type="Number" integer="true">
        /// The ColumnID of the column which is uniquely identify it among the other columns.
        /// </param>
        /// <returns type="Number" integer="true">Returns the Index if found otherwise -1.</returns>

        //Argument validation
        var e = Function._validateParams(arguments, [{ name: 'columnID', type: Number}]);
        if (e) throw e;

        var columns = this.get_columns();

        if (columns != null) {
            var columnLength = columns.length;

            if (columnLength > 0) {
                for (var i = 0; i < columnLength; i++) {
                    if (columns[i].get_columnID() == columnID) {
                        return i;
                    }
                }
            }
        }

        return -1;
    },

    getColumnIndexByDataField: function(dataField) {
        /// <summary>
        /// Returns the Index of the specified column dataField, if the same data field is used for more than one column then only returns the first index.
        /// </summary>
        /// <param name="dataField" type="String">
        /// The data field of the column.
        /// </param>
        /// <returns type="Number" integer="true">Returns the Index if found otherwise -1.</returns>

        //Argument validation
        var e = Function._validateParams(arguments, [{ name: 'dataField', type: String}]);
        if (e) throw e;

        // Since we are supporing drag n drop it is not possible
        // that the index of the column will be static,
        // that is way we need a helper function which will
        // resolve the proper index based upon the header text.
        // **** Warning: if same data field is used for more than one column, it will only return the first

        var columns = this.get_columns();
        if (columns != null) {
            var columnLength = columns.length;
            if (columnLength > 0) {
                var column;
                for (var i = 0; i < columnLength; i++) {
                    column = columns[i];
                    if ((column.get_dataField) && (column.get_dataField() == dataField)) {
                        return i;
                    }
                }
            }
        }

        return -1;
    },

    getColumnIndexByHeaderText: function(headerText) {
        /// <summary>
        /// Returns the Index of the specified column headerText, if the same header text is used for more than one column then only returns the first index.
        /// </summary>
        /// <param name="headerText" type="String">
        /// The header text of the column.
        /// </param>
        /// <returns type="Number" integer="true">Returns the Index if found otherwise -1.</returns>

        //Argument validation
        var e = Function._validateParams(arguments, [{ name: 'headerText', type: String}]);
        if (e) throw e;

        //Since we are supporing drag n drop it is not possible
        //that the index of the column will be static,
        //that is way we need a helper function which will
        //resolve the proper index based upon the header text.
        //**** Warning: if Same header is used for more than one column
        //it will only return the first

        var columns = this.get_columns();

        if (columns != null) {
            var columnLength = columns.length;

            if (columnLength > 0) {
                for (var i = 0; i < columnLength; i++) {
                    if (columns[i].get_headerText() == headerText) {
                        return i;
                    }
                }
            }
        }

        return -1;
    },

    loadColumnsFromProfile: function(propertyName) {
        /// <summary>
        /// Loads the column sequence from the specified property name of the ASP.net Profile. The Ajax profile Service must be configured to call this method.
        //  It fires the columnsLoadedFromProfile event after loading the columns.
        /// </summary>
        /// <param name="propertyName" type="String">
        /// The name of the property where the column sequence is stored.
        /// </param>

        //Argument validation
        var e = Function._validateParams(arguments, [{ name: 'propertyName', type: String}]);
        if (e) throw e;

        if ((typeof (Sys.Services) == 'undefined') || (typeof (Sys.Services.ProfileService) === 'undefined')) {
            throw Error.invalidOperation('ProfileService must be configured before calling this method.');
        }

        this._profileLoadedHandler = Function.createDelegate(this, this._onProfileLoaded);
        Sys.Services.ProfileService.load([propertyName], this._profileLoadedHandler, null, propertyName);
    },

    saveColumnsToProfile: function(propertyName) {
        /// <summary>
        /// Saves the column sequence in the specified property name of the ASP.net Profile. The Ajax profile Service must be configured to call this method.
        //  It fires the columnsSavedToProfile event after saving the columns. The consumer of this control required to call this method
        /// in the columnDropped event to persist the column sequence.
        /// </summary>
        /// <param name="propertyName" type="String">
        /// The name of the property where the column sequence will be stored.
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'propertyName', type: String}]);
        if (e) throw e;

        if ((typeof (Sys.Services) == 'undefined') || (typeof (Sys.Services.ProfileService) === 'undefined')) {
            throw Error.invalidOperation('ProfileService must be configured before calling this method.');
        }

        var columns = this.get_columns();
        var profileColumns = new Array();

        for (var i = 0; i < columns.length; i++) {
            profileColumns.push({ id: columns[i].get_columnID(), idx: i });
        }

        var serializedColumns = Sys.Serialization.JavaScriptSerializer.serialize(profileColumns);

        if (serializedColumns) {
            if (serializedColumns.length > 0) {
                this._profileSavedHandler = Function.createDelegate(this, this._onProfileSaved);

                Sys.Services.ProfileService.properties[propertyName] = serializedColumns;
                Sys.Services.ProfileService.save([propertyName], this._profileSavedHandler);
            }
        }
    },

    add_columnsLoadedFromProfile: function(handler) {
        /// <summary>
        /// This event is raised when the columns sequence are loaded form the Ajax Profile Service.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('columnsLoadedFromProfile', handler);
    },

    remove_columnsLoadedFromProfile: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('columnsLoadedFromProfile', handler);
    },

    add_columnsSavedToProfile: function(handler) {
        /// <summary>
        /// This event is raised when the columns sequence are saved in the Ajax Profile Service.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('columnsSavedToProfile', handler);
    },

    remove_columnsSavedToProfile: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('columnsSavedToProfile', handler);
    },

    add_columnDragStart: function(handler) {
        /// <summary>
        /// This event is raised when the user starts dragging of a column.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('columnDragStart', handler);
    },

    remove_columnDragStart: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('columnDragStart', handler);
    },

    add_columnDropped: function(handler) {
        /// <summary>
        /// This event is raised when the user drops a column and the drop is sucessfull.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('columnDropped', handler);
    },

    remove_columnDropped: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('columnDropped', handler);
    },

    add_sortCommand: function(handler) {
        /// <summary>
        /// This event is raised when a column header is clicked to sort.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('sortCommand', handler);
    },

    remove_sortCommand: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('sortCommand', handler);
    },

    add_selectedIndexChanged: function(handler) {
        /// <summary>
        /// This event is raised when a row is selected with a Select Command.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('selectedIndexChanged', handler);
    },

    remove_selectedIndexChanged: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('selectedIndexChanged', handler);
    },
    add_insertCommand: function(handler) {
        /// <summary>
        /// This event is raised when the Insert button is clicked for a row in the GridView control.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('insertCommand', handler);
    },

    remove_insertCommand: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('insertCommand', handler);
    },


    add_editCommand: function(handler) {
        /// <summary>
        /// This event is raised when the Edit button is clicked for a row in the GridView control.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('editCommand', handler);
    },

    remove_editCommand: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('editCommand', handler);
    },

    add_updateCommand: function(handler) {
        /// <summary>
        /// This event is raised when the Update button is clicked for a row in the GridView control.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('updateCommand', handler);
    },

    remove_updateCommand: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('updateCommand', handler);
    },

    add_cancelCommand: function(handler) {
        /// <summary>
        /// This event is raised when the Cancel button is clicked for a row in the GridView control.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('cancelCommand', handler);
    },

    remove_cancelCommand: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('cancelCommand', handler);
    },

    add_deleteCommand: function(handler) {
        /// <summary>
        /// This event is raised when the Delete button is clicked for a row in the GridView control.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('deleteCommand', handler);
    },

    remove_deleteCommand: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('deleteCommand', handler);
    },

    add_rowCommand: function(handler) {
        /// <summary>
        /// This event is raised when a button which has associated commandName is clicked in the GridView row.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('rowCommand', handler);
    },

    remove_rowCommand: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('rowCommand', handler);
    },

    add_rowCreated: function(handler) {
        /// <summary>
        /// This event is raised when arow in the GridView control is created.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('rowCreated', handler);
    },

    remove_rowCreated: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('rowCreated', handler);
    },

    add_rowDataBound: function(handler) {
        /// <summary>
        /// This event is raised when a row in the GridView control is going to be data-bound.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('rowDataBound', handler);
    },

    remove_rowDataBound: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('rowDataBound', handler);
    },

    add_rowGrouped: function(handler) {
        /// <summary>
        /// This event is raised when a row in the GridView control is going to be data-bound.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('rowGrouped', handler);
    },

    remove_rowGrouped: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('rowGrouped', handler);
    },

    add_rowMouseOver: function(handler) {
        /// <summary>
        /// This event is raised when the mouse hoveres over a row in the GridView control.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('rowMouseOver', handler);
    },

    remove_rowMouseOver: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('rowMouseOver', handler);
    },

    add_rowMouseOut: function(handler) {
        /// <summary>
        /// This event is raised when the mouse hoveres over a row in the GridView control.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('rowMouseOut', handler);
    },

    remove_rowMouseOut: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('rowMouseOut', handler);
    },

    add_dataBound: function(handler) {
        /// <summary>
        /// This event is raised after the GridView control binds to a data source.
        /// </summary>
        /// <param name="handler" type="Function">
        /// Event handler
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().addHandler('dataBound', handler);
    },

    remove_dataBound: function(handler) {
        var e = Function._validateParams(arguments, [{ name: 'handler', type: Function}]);
        if (e) throw e;

        this.get_events().removeHandler('dataBound', handler);
    },

    _raiseColumnDragStart: function(column) {
        this._raiseEvent('columnDragStart', this, new $ADC.GridViewColumnDragStartEventArgs(column));
    },

    _raiseColumnDropped: function(column, oldIndex, newIndex) {
        this._raiseEvent('columnDropped', this, new $ADC.GridViewColumnDroppedEventArgs(column, oldIndex, newIndex));
    },

    _raiseSort: function(e, context) {
        context.sender._raiseEvent('sortCommand', context.sender, new $ADC.GridViewSortCommandEventArgs(context.sortColumn, context.sortOrder));
    },

    _raiseMouseOver: function(e, context) {
        context.sender._raiseEvent('rowMouseOver', context.sender, new $ADC.GridViewRowEventArgs(context.row));
    },

    _raiseMouseOut: function(e, context) {
        context.sender._raiseEvent('rowMouseOut', context.sender, new $ADC.GridViewRowEventArgs(context.row));
    },

    _raiseDataBound: function(e, context) {
        context.sender._raiseEvent('dataBound', context.sender, Sys.EventArgs.Empty);
    },

    _raiseCommand: function(e, context) {
        var commandName = '';
        var commandArgument = '';

        // Get the CommandName from the DOM element.
        if (e.target.commandName) {
            commandName = e.target.commandName;
        }
        else {
            var commandNameAttribute = e.target.attributes['commandName'];

            if (commandNameAttribute) {
                if (commandNameAttribute.value) {
                    commandName = commandNameAttribute.value;
                }
                else if (commandNameAttribute.nodeValue) {
                    commandName = commandNameAttribute.nodeValue;
                }
            }
        }

        // Get the CommandArgument from the DOM element.
        if (e.target.commandArgument) {
            commandArgument = e.target.commandArgument;
        }
        else {
            var commandArgumentAttribute = e.target.attributes['commandArgument'];

            if (commandArgumentAttribute) {
                if (commandArgumentAttribute.value) {
                    commandArgument = commandArgumentAttribute.value;
                }
                else if (commandArgumentAttribute.nodeValue) {
                    commandArgument = commandArgumentAttribute.nodeValue;
                }
            }
        }

        if ((commandName.length > 0) && (context.row.get_isDataRowType())) {
            var handler;
            // Get the handler for the command.
            if (commandName === context.sender.SelectCommandName) {
                context.sender._selectCommandHandler(e, context.row.get_rowIndex());
            }
            else if (commandName === context.sender.EditCommandName) {
                handler = context.sender.get_events().getHandler('editCommand');
            }
            else if (commandName === context.sender.InsertCommandName) {
                handler = context.sender.get_events().getHandler('insertCommand');
            }
            else if (commandName === context.sender.UpdateCommandName) {
                handler = context.sender.get_events().getHandler('updateCommand');
            }
            else if (commandName === context.sender.CancelCommandName) {
                handler = context.sender.get_events().getHandler('cancelCommand');
            }
            else if (commandName === context.sender.DeleteCommandName) {
                handler = context.sender.get_events().getHandler('deleteCommand');
            }

            // Call the handler from the command.
            if (handler) {
                handler(context.sender, new $ADC.GridViewCommandEventArgs(commandName, commandArgument, e.target, context.row));
            }

            context.sender._raiseEvent('rowCommand', context.sender, new $ADC.GridViewCommandEventArgs(commandName, commandArgument, e.target, context.row));
        }
    },

    _raiseEvent: function(eventID, sender, args) {
        var handler = this.get_events().getHandler(eventID);
        if (handler) {
            if (args == null)
                args = Sys.EventArgs.Empty;

            handler(sender, args);
        }
    },

    _internalInsertRows: function(value) {
        var table = this.get_element();
        var tBody = table.tBodies[0];
        var dataSource = value;
        var dataLength = dataSource.length;
        var columnsLength = this._columns.length;

        var tr;
        var td;
        var rowType;
        var style;
        var row;
        var handler = null;
        var isAlt = false;

        // get styles
        var rowStyle = this.get_rowStyle();
        var alternatingRowStyle = this.get_alternatingRowStyle();

        var dataKeyName = this.get_dataKeyName();
        var hasDataKeyName = false;
        var dataRow;

        // get last rowType of the existing dataSource
        var previousRowCount = this.get_rows().length - 1;
        var lastRowType = this.get_rows()[previousRowCount].get_rowType();

        if (lastRowType == $ADC.GridViewRowType.Row) {
            isAlt = true;
        }

        for (var i = 0; i < dataLength; i++) {
            tr = document.createElement('tr');
            tBody.appendChild(tr);

            dataRow = dataSource[i];
            rowType = $ADC.GridViewRowType.Row;
            style = rowStyle;

            if (!$ADC.Util.isEmptyString(dataKeyName)) {
                Array.add(this._dataKeys, dataRow[dataKeyName]);
            }

            if (isAlt) {
                rowType = $ADC.GridViewRowType.AlternatingRow;

                if (alternatingRowStyle != null) {
                    style = alternatingRowStyle;
                }
            }

            previousRowCount = previousRowCount + 1;
            namingContainer = this._getNamingContainer(rowType, previousRowCount);
            row = new $ADC.GridViewRow(namingContainer, tr, previousRowCount, rowType, dataRow, this);
            Array.add(this._rows, row);

            if (style != null) {
                style.apply(tr);
            }

            for (var j = 0; j < columnsLength; j++) {
                column = this._columns[j];

                if (column.get_visible() == true) {
                    td = document.createElement('td');
                    tr.appendChild(td);

                    column.renderData(dataRow, row, td);
                }
            }

            isAlt = !isAlt;

            // add event handlers
            this._raiseEvent('rowCreated', this, new $ADC.GridViewRowEventArgs(row));
            this._raiseEvent('rowDataBound', this, new $ADC.GridViewRowEventArgs(row));

            if (this.get_events().getHandler('rowMouseOver')) {
                $ADC.Util.addCallbackEventHandler(row.get_container(), 'mouseover', this._raiseMouseOver, { sender: this, row: row });
            }
            if (this.get_events().getHandler('rowMouseOut')) {
                $ADC.Util.addCallbackEventHandler(row.get_container(), 'mouseout', this._raiseMouseOut, { sender: this, row: row });
            }
        }

        this._raiseEvent('dataBound', this);
    },

    _setGroupContainer: function(groupField) {

    },

    _internalDataBind: function(animate) {
        var table = this.get_element();
        table.style.visibility = 'hidden';

        if (this._headerRow != null) {
            this._headerRow.dispose();
            this._headerRow = null;
        }

        if (this._footerRow != null) {
            this._footerRow.dispose();
            this._footerRow = null;
        }

        $ADC.Util.clearContent(table);
        this._cleanupRows();
        Array.clear(this._dataKeys);

        var dataSource = this.get_dataSource();
        var tBody;

        if ((dataSource == null) || (dataSource.length == 0)) {
            var trEmpty;
            var tdEmpty;

            if (!$ADC.Util.isEmptyString(this.get_emptyDataTemplate())) {
                tBody = document.createElement('tbody');
                table.appendChild(tBody);

                trEmpty = document.createElement('tr');
                tBody.appendChild(trEmpty);

                tdEmpty = document.createElement('td');
                trEmpty.appendChild(tdEmpty);

                tdEmpty.innerHTML = this.get_emptyDataTemplate();

                if (this.get_emptyDataRowStyle() != null) {
                    this.get_emptyDataRowStyle().apply(trEmpty);
                    this.get_emptyDataRowStyle().apply(tdEmpty);
                }
            }
            else if (!$ADC.Util.isEmptyString(this.get_emptyDataText())) {
                tBody = document.createElement('tbody');
                table.appendChild(tBody);

                trEmpty = document.createElement('tr');
                tBody.appendChild(trEmpty);

                tdEmpty = document.createElement('td');
                trEmpty.appendChild(tdEmpty);
                tdEmpty.style.textAlign = 'left';

                tdEmpty.appendChild(document.createTextNode(this.get_emptyDataText()));
            }

            table.style.visibility = 'visible';
            return;
        }

        var dataKeyName = this.get_dataKeyName();
        var hasDataKeyName = false;
        var dataRow;

        if (!$ADC.Util.isEmptyString(dataKeyName)) {
            hasDataKeyName = true;

            dataRow = dataSource[0];

            var exists = false;

            //We can iterate it since all the JavaScript object is a Dictionary
            for (var property in dataRow) {
                if ((!property.startsWith('__')) && (property == dataKeyName)) // Excluding the Ajax Framework Properties
                {
                    exists = true;
                    break;
                }
            }

            if (!exists) {
                //DataKeyName does not exist, so raise exception
                throw Error.invalidOperation('Specified dataKeyName does not exists in dataSource.');
            }
        }

        var column;
        var i = 0;

        if ((this._columns == null) || (this._columns.length == 0)) {
            //Columns collection has not been specified, so we have to
            //discover it from the datasource, this is same as GridView AutoGenerateColumn = True
            this._columns = new Array();
            dataRow = dataSource[0];

            for (var property in dataRow) {
                if (!property.startsWith('__')) // Excluding the Ajax Framework Properties
                {
                    // Is the type of data Boolean ?
                    if (typeof (eval('dataRow.' + property)) == "boolean")
                        column = new $ADC.GridViewCheckBoxColumn();
                    else
                        column = new $ADC.GridViewBoundColumn();

                    column.set_headerText(property);
                    column.set_dataField(property);
                    column.set_allowDragAndDrop(false);

                    Array.add(this._columns, column);
                    column.set_columnID(this._columns.length);
                }
            }
        }

        if ((this.get_autoGenerateDeleteButton()) || (this.get_autoGenerateEditButton()) || (this.get_autoGenerateSelectButton())) {
            column = new $ADC.GridViewCommandColumn();

            column.set_buttonType($ADC.GridViewColumnButtonType.Button);
            column.set_showDeleteButton(this.get_autoGenerateDeleteButton());
            column.set_showEditButton(this.get_autoGenerateEditButton());
            column.set_showCancelButton(this.get_autoGenerateEditButton());
            column.set_showSelectButton(this.get_autoGenerateSelectButton());

            Array.insert(this._columns, 0, column);
        }

        var columnsLength = this._columns.length;

        //Setting the owner and releasing previous resources which is associated with each column
        for (var i = 0; i < columnsLength; i++) {
            this._columns[i].set_owner(this);
            this._columns[i].releaseResource();
        }

        var showHeader = this.get_showHeader();

        var allowDragAndDrop = false;

        if (showHeader == true) {
            for (var i = 0; i < columnsLength; i++) {
                if (this._columns[i].get_allowDragAndDrop() === true) {
                    allowDragAndDrop = true;
                    break;
                }
            }
        }

        var tBody = document.createElement('tbody');
        table.appendChild(tBody);

        var grid = this;
        var th;
        var groupField = this.get_groupField();
        var trGroup = document.createElement('tr');
        var tdGroup = document.createElement('td');
        var id = $ADC.Util.getRandomId();
        tdGroup.id = id;

        tdGroup.colSpan = columnsLength + 1;
        tdGroup.innerHTML = "Drag column here to group by";
        tdGroup.className = "groupingDropContainer";
        trGroup.appendChild(tdGroup);
        tBody.appendChild(trGroup);

        if (!$ADC.Util.isEmptyString(groupField)) 
        {
            var columnIndex = this.getColumnIndexByDataField(groupField);
            if (columnIndex != -1) {
                var item = this.get_columns()[columnIndex];
                var groupedColumnHeaderText = item.get_headerText();
                var groupedSortColumn = item.get_sortField();
                var groupedColumnId = "group_" + groupedSortColumn;
                var spnGroupedColumn = document.createElement("span");

                spnGroupedColumn.className = "groupedColumn";
                spnGroupedColumn.style.cursor = "move";
                spnGroupedColumn.style.zIndex = '9999';
                spnGroupedColumn.innerHTML = groupedColumnHeaderText;
                spnGroupedColumn.id = groupedColumnId;

                // if there is only 1 child node, then there is no group by yet. It only has the default grouping
                // text information.
                if (tdGroup.childNodes.length == 1) {
                    tdGroup.innerHTML = "";
                }

                tdGroup.appendChild(spnGroupedColumn);
                $("#" + groupedColumnId).data("draggedItem", { item: item, isGroupingHeader: true, groupingContainer: tdGroup, groupedColumn: spnGroupedColumn });
                $("#" + groupedColumnId).draggable(
                {
                    helper: 'clone'
                });
            }

            $("#" + id).droppable(
            {
                accept: function(draggable) {
                    return true
                },
                drop: function(ev, ui) {

                    var draggedItem = ui.draggable.data("draggedItem");
                    var groupedColumnHeaderText = draggedItem.item.get_headerText();
                    var groupedSortColumn = draggedItem.item.get_sortField();
                    var groupedColumnId = "group_" + groupedSortColumn;
                    var spnGroupedColumn = document.createElement("span");

                    spnGroupedColumn.className = "groupedColumn";
                    spnGroupedColumn.style.cursor = "move";
                    spnGroupedColumn.style.zIndex = '9999';
                    spnGroupedColumn.innerHTML = groupedColumnHeaderText;
                    spnGroupedColumn.id = groupedColumnId;

                    // if there is only 1 child node, then there is no group by yet. It only has the default grouping
                    // text information.
                    if (tdGroup.childNodes.length == 1) {
                        tdGroup.innerHTML = "";
                    }

                    tdGroup.appendChild(spnGroupedColumn);
                    $("#" + groupedColumnId).data("draggedItem", { item: draggedItem.item, isGroupingHeader: true, groupingContainer: tdGroup, groupedColumn: spnGroupedColumn });
                    $("#" + groupedColumnId).draggable(
                    {
                        helper: 'clone'
                    });

                    grid.set_groupField(groupedSortColumn);
                    grid.set_sortColumn(groupedSortColumn);
                    grid.dataBind();
                },
                over: function(ev, ui) {
                    //var draggedItem = ui.draggable.data("draggedItem");
                    //item.onDragEnterTarget(draggedItem.item);
                }
            });
        }

        var thead = document.createElement('thead');
        table.appendChild(thead);

        var trHead = document.createElement('tr');
        tBody.appendChild(trHead);

        var namingContainer;

        namingContainer = this._getNamingContainer($ADC.GridViewRowType.Header, -1);
        this._headerRow = new $ADC.GridViewRow(namingContainer, trHead, -1, $ADC.GridViewRowType.Header, null, this);

        if (this.get_headerStyle() != null) {
            this.get_headerStyle().apply(trHead);
        }

        var th;
        var groupField = this.get_groupField();

        if (showHeader == true) {
            if (!$ADC.Util.isEmptyString(groupField)) {
                th = document.createElement('th');
                th.style.width = "20px";
                trHead.appendChild(th);
            }

            for (var i = 0; i < columnsLength; i++) {
                column = this._columns[i];
                if (column.get_visible() == true) {
                    th = document.createElement('th');
                    trHead.appendChild(th);

                    column.set_headerContainer(th);
                    column.renderHeader(this._headerRow);
                }
            }
        }

        this._raiseEvent('rowCreated', this, new $ADC.GridViewRowEventArgs(this._headerRow));
        this._raiseEvent('rowDataBound', this, new $ADC.GridViewRowEventArgs(this._headerRow));

        var tr;
        var td;
        var dataLength = dataSource.length;

        var rowType;
        var style;
        var row;
        var isAlt = false;

        var rowStyle = this.get_rowStyle();
        var alternatingRowStyle = this.get_alternatingRowStyle();
        var selectedRowStyle = this.get_selectedRowStyle();
        var editRowStyle = this.get_editRowStyle();
        var insertRowStyle = this.get_insertRowStyle();

        var sortColumn = this.get_sortColumn();

        if (!$ADC.Util.isEmptyString(sortColumn) && !$ADC.Util.isEmptyString(groupField)) {
            if (sortColumn != groupField) {
                groupField = sortColumn;
            }
        }

        var m_category = "oeaptjatiaptiapt23atapgjaaoatpat";
        var m_lastCategory = "";
        var m_count = 0;
        var mCounts = new Array();
        var mCategories = new Array();

        // get all values based on which to be grouped
        if (!$ADC.Util.isEmptyString(groupField)) {
            for (var i = 0; i < dataLength; i++) {
                dataRow = dataSource[i];
                if (dataRow[groupField].toString() != m_category) {
                    if (m_category != "oeaptjatiaptiapt23atapgjaaoatpat") {
                        Array.add(mCategories, m_category);
                        Array.add(mCounts, m_count);
                    }

                    m_category = dataRow[groupField].toString();
                    m_lastCategory = m_category;
                    m_count = 1;
                }
                else {
                    m_count++;
                }
            }
        }

        //add the last grouping category to the array
        Array.add(mCategories, m_category);
        Array.add(mCounts, m_count);

        var groupCount = 0;
        var groupRowCount = 0;

        var groupingStyle = this.get_groupingStyle();

        for (var i = 0; i < dataLength; i++) {
            if (mCategories.length > 0 && !$ADC.Util.isEmptyString(groupField)) {
                if (i == 0 || i == groupRowCount) {
                    var groupName = mCategories[groupCount];
                    var groupTotal = mCounts[groupCount];

                    tr = document.createElement('tr');
                    tBody.appendChild(tr);

                    td = document.createElement('td');
                    tr.appendChild(td);

                    td.colSpan = columnsLength + 1;
                    var info = groupField + ": " + groupName + " (" + groupTotal + ")";
                    td.appendChild(document.createTextNode(info));

                    groupCount += 1;
                    groupRowCount += groupTotal;

                    if (groupingStyle != null) {
                        groupingStyle.apply(tr);
                    }

                    this._raiseEvent('rowGrouped', this, { cell: td, groupName: groupName, groupTotal: groupTotal });
                }
            }

            dataRow = dataSource[i];

            if (hasDataKeyName) {
                Array.add(this._dataKeys, dataRow[dataKeyName]);
            }

            tr = document.createElement('tr');
            tBody.appendChild(tr);

            rowType = $ADC.GridViewRowType.Row;
            style = rowStyle;

            if (isAlt) {
                rowType = $ADC.GridViewRowType.AlternatingRow;

                if (alternatingRowStyle != null) {
                    style = alternatingRowStyle;
                }
            }

            if (this._selectedIndex == i) {
                rowType = $ADC.GridViewRowType.SelectedRow;

                if (selectedRowStyle != null) {
                    style = selectedRowStyle;
                }
            }
            else if (this._editIndex == i) {
                rowType = $ADC.GridViewRowType.EditRow;

                if (editRowStyle != null) {
                    style = editRowStyle;
                }
            }

            namingContainer = this._getNamingContainer(rowType, i);
            row = new $ADC.GridViewRow(namingContainer, tr, i, rowType, dataRow, this);
            Array.add(this._rows, row);

            if (style != null) {
                style.apply(tr);
            }

            if (!$ADC.Util.isEmptyString(groupField)) {
                // add a dummy cell to show a hierachy effect    
                td = document.createElement('td');
                tr.appendChild(td);
            }

            for (var j = 0; j < columnsLength; j++) {
                column = this._columns[j];

                if (column.get_visible() == true) {
                    td = document.createElement('td');
                    tr.appendChild(td);

                    column.renderData(dataRow, row, td);
                }
            }

            isAlt = !isAlt;

            this._raiseEvent('rowCreated', this, new $ADC.GridViewRowEventArgs(row));
            this._raiseEvent('rowDataBound', this, new $ADC.GridViewRowEventArgs(row));

            if (this.get_events().getHandler('rowMouseOver')) {
                $ADC.Util.addCallbackEventHandler(row.get_container(), 'mouseover', this._raiseMouseOver, { sender: this, row: row });
            }

            if (this.get_events().getHandler('rowMouseOut')) {
                $ADC.Util.addCallbackEventHandler(row.get_container(), 'mouseout', this._raiseMouseOut, { sender: this, row: row });
            }
        }

        var insertRow;

        //append a row for inserting data at the table bottom
        if (this.get_autoGenerateInsertButton()) {
            tr = document.createElement('tr');
            tBody.appendChild(tr);

            if (!$ADC.Util.isEmptyString(groupField)) {
                // add a dummy cell to show a hierachy effect    
                td = document.createElement('td');
                tr.appendChild(td);
            }

            rowType = $ADC.GridViewRowType.InsertRow;

            if (insertRowStyle != null) {
                style = insertRowStyle;
            }

            namingContainer = this._getNamingContainer(rowType, i);
            row = new $ADC.GridViewRow(namingContainer, tr, i, rowType, dataRow, this);

            //Array.add(this._rows, row); 

            if (style != null) {
                style.apply(tr);
            }

            for (var j = 0; j < columnsLength; j++) {
                column = this._columns[j];

                dataRow[j] = "";
                if (column.get_visible() == true) {
                    td = document.createElement('td');
                    column.renderData(dataRow, row, td);
                    tr.appendChild(td);
                }
            }

            tr = document.createElement('tr');
            tBody.appendChild(tr);
            td = document.createElement('td');
            tr.appendChild(td);
            td.colSpan = columnsLength;

            var insertButton;

            insertButton = document.createElement('a');
            insertButton.appendChild(document.createTextNode("Insert Row"));
            insertButton.setAttribute('href', 'javascript:void(0)');
            insertButton.commandName = this.InsertCommandName;

            $ADC.Util.addCallbackEventHandler(insertButton, 'click', this._raiseCommand, { sender: this, row: row });

            td.appendChild(insertButton);
        }


        var tfoot = document.createElement('tfoot');
        table.appendChild(tfoot);

        var trFoot = document.createElement('tr');
        tfoot.appendChild(trFoot);

        namingContainer = this._getNamingContainer($ADC.GridViewRowType.Footer, -1);
        this._footerRow = new $ADC.GridViewRow(namingContainer, trFoot, -1, $ADC.GridViewRowType.Footer, null, this);

        if (this.get_footerStyle() != null) {
            this.get_footerStyle().apply(trFoot);
        }

        if (!$ADC.Util.isEmptyString(groupField)) {
            // add a dummy cell to show a hierachy effect    
            td = document.createElement('td');
            tfoot.appendChild(td);
        }

        if (this.get_showFooter() == true) {
            for (var i = 0; i < columnsLength; i++) {
                column = this._columns[i];

                if (column.get_visible() == true) {
                    td = document.createElement('td');
                    trFoot.appendChild(td);

                    column.set_footerContainer(td);
                    column.renderFooter(this._footerRow);
                }
            }
        }

        this._raiseEvent('rowCreated', this, new $ADC.GridViewRowEventArgs(this._footerRow));
        this._raiseEvent('rowDataBound', this, new $ADC.GridViewRowEventArgs(this._footerRow));

        this._hasBinded = true;

        if (allowDragAndDrop) {
            //The Following will prevent the content selection while dragging

            if (Sys.Browser.agent == Sys.Browser.InternetExplorer) {
                table.style.userSelect = 'none';
            }
            else if (Sys.Browser.agent == Sys.Browser.Safari) {
                table.style.KhtmlUserSelect = 'none';
            }
            else {
                table.style.MozUserSelect = 'none'; // Both Firefox and Opera are supposed to support it
            }
        }

        table.style.visibility = 'visible';

        if (animate == true) {
            if (this._canAnimate()) {
                if (this._animation == null) {
                    this._animation = $ADC.Util.createDataBindAnimation(this.get_animationDuration(), this.get_animationFps(), this);
                }

                if (Sys.Browser.agent == Sys.Browser.InternetExplorer) {
                    var backColor = $ADC.Style.getStyleValue(table, 'backgroundColor');

                    if ((!backColor) || (backColor == '') || (backColor == 'transparent') || (backColor == 'rgba(0, 0, 0, 0)')) {
                        table.style.backgroundColor = $ADC.Style.getInheritedBackgroundColor(table);
                    }
                }

                this._animation.play();
            }
        }

        this._raiseEvent('dataBound', this, Sys.EventArgs.Empty);
    },

    _onProfileLoaded: function(result, propertyName) {
        var serializedColumns = Sys.Services.ProfileService.properties[propertyName];

        if (serializedColumns) {
            if (serializedColumns.length > 0) {
                var profileColumns = Sys.Serialization.JavaScriptSerializer.deserialize(serializedColumns);

                if ((profileColumns != null) && (profileColumns.length > 0)) {
                    for (var i = 0; i < profileColumns.length; i++) {
                        var oldIndex = this.getColumnIndexByColumnID(profileColumns[i].id);
                        var newIndex = profileColumns[i].idx;

                        if ((oldIndex > -1) && (oldIndex != newIndex)) {
                            var column = this._columns[oldIndex];
                            //First remove the column from that index.
                            Array.removeAt(this._columns, oldIndex);
                            //Now insert it in new index
                            Array.insert(this._columns, newIndex, column);
                        }
                    }
                }
            }
        }

        this._raiseEvent('columnsLoadedFromProfile', this, Sys.EventArgs.Empty);
    },

    _onProfileSaved: function(result, propertyName) {
        this._raiseEvent('columnsSavedToProfile', this, Sys.EventArgs.Empty);
    },

    _selectCommandHandler: function(e, index) {
        /// <summary>
        /// Handles all commands from the GridView to SelectCommand.
        /// </summary>
        /// <param name="e" type="Event">
        /// The selection state that must be set to all rows.
        /// </param>
        /// <param name="index" type="Event">
        /// The index of row.
        /// </param>

        var shiftPressed = (e) ? e.shiftKey : false;
        // Isn't ShiftKey pressed ? 
        if (!shiftPressed) {
            this.selectRow(index); // Then select just the current row.
        }
        else // Select all rows until the clicked row is not reached.
        {
            var indexes = this.get_selectedIndexes();
            var indexSelected = (Array.binarySearch(indexes, index) > -1);
            this._internalSelectRow(index);

            // What is the direction to select rows ?
            if (this._lastSelectedIndex < index) // Go to next direction
            {
                i = (indexSelected) ? this._lastSelectedIndex : this._lastSelectedIndex + 1;
                for (; i <= index; i++) {
                    if ((i != index) && ((Array.binarySearch(indexes, i) > -1) == indexSelected)) {
                        this._internalSelectRow(i);
                    }
                }
            }
            else if (this._lastSelectedIndex > index) // Go to previous direction
            {
                i = (indexSelected) ? this._lastSelectedIndex : this._lastSelectedIndex - 1;
                for (; i >= index; i--) {
                    if ((i != index) && ((Array.binarySearch(indexes, i) > -1) == indexSelected)) {
                        this._internalSelectRow(i);
                    }
                }
            }
        }
        // Set the current index as the last.
        this._lastSelectedIndex = index;
        // Render new style rows.
        this._styleApplyAllRows();
    },

    selectAllRows: function(selected) {
        /// <summary>
        /// Change the selected state of all rows.
        /// </summary>
        /// <param name="selected" type="Boolean">
        /// The selection state that must be set to all rows.
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'selected', type: Boolean}]);
        if (e) throw e;

        var length = this._rows.length;
        if (length == 0)
            return;

        var indexOnArray;
        // Iterate all row indexes to select or not.
        for (var i = 0; i < length; i++) {
            // Is the index select state equals already set ?
            if (((indexOnArray = Array.binarySearch(this.get_selectedIndexes(), i)) > -1) != selected) {
                this._internalSelectRow(i, indexOnArray);
            }
        }

        this._styleApplyAllRows();
    },

    selectRow: function(index) {
        /// <summary>
        /// Change the "selected state" of row based on its index.
        /// </summary>
        /// <param name="index" type="Number" integer="True">
        /// The index of row.
        /// </param>

        var e = Function._validateParams(arguments, [{ name: 'index', type: Number, integer: true}]);
        if (e) throw e;

        // No need to processed.
        if ((this._rows.length == 0)) {
            return;
        }
        this._internalSelectRow(index)
        this._styleApplyRow(index);
    },

    _internalSelectRow: function(index, indexOnArray) {
        /// <summary>
        /// Change the "selected state" of row based on the search on selected indexes array.
        /// </summary>
        /// <param name="index" type="Number" integer="True">
        /// The index of row.
        /// </param>
        /// <param name="indexOnArray" type="Number" integer="True">
        /// The index of row in the selected array.
        /// </param>

        var indexes = this.get_selectedIndexes();
        // Is it needed to search the index to be selected ?
        if (!indexOnArray)
            indexOnArray = Array.binarySearch(indexes, index);

        // Is the index to be selected already selected ?
        if (indexOnArray >= 0) {
            indexes.splice(indexOnArray, 1); // Removes the index.
        }
        else {
            Array.insert(indexes, Array.binarySearch(indexes, index, true), index);
        }

        // Is not the index to be selected already selected ? 
        this._rows[index].set_isSelected((indexOnArray < 0));

        // Since the index has changed raise the property change event
        this.raisePropertyChanged('selectedIndexes');
        this._raiseEvent('selectedIndexChanged', this, new $ADC.GridViewRowEventArgs(this._rows[index]));
    },

    _styleApplyAllRows: function() {
        /// <summary>
        /// Apply styles for all rows.
        /// </summary>

        var length = this._rows.length;
        // No need to processed.
        if (length == 0)
            return;

        for (var i = 0; i < length; i++) {
            this._styleApplyRow(i);
        }
    },

    _styleApplyRow: function(index) {
        /// <summary>
        /// Apply styles for a row.
        /// </summary>
        /// <param name="index" type="Number" integer="True">
        /// The index of row.
        /// </param>

        // Get the Select CheckBox element.
        var selected = this._rows[index].get_isSelected();
        var checkBox = $get(String.format($ADC.GridViewCommandColumn.CheckBoxIDFormat, this.get_id(), index));
        if (checkBox) {
            checkBox.checked = selected;
        }

        // Get styles for rows
        var rowStyle = this.get_rowStyle();
        var alternatingRowStyle = this.get_alternatingRowStyle();
        var selectedRowStyle = this.get_selectedRowStyle();
        var editRowStyle = this.get_editRowStyle();
        var style = rowStyle; // Used to apply style to row, at the end.		

        var rowType = $ADC.GridViewRowType.Row;

        // Is selected row ?
        if ((selected) && (selectedRowStyle != null)) {
            style = selectedRowStyle;
            rowType = $ADC.GridViewRowType.SelectedRow;
        }
        // Is alternating row ?
        else if ((index % 2) && (alternatingRowStyle != null)) {
            style = alternatingRowStyle;
            rowType = $ADC.GridViewRowType.AlternatingRow;
        }
        // Is row in edit mode ?
        else if ((this._editIndex == index) && (editRowStyle != null)) {
            style = editRowStyle;
            rowType = $ADC.GridViewRowType.EditRow;
        }

        // Apply style to the row.
        if (style != null) {
            style.apply(this._rows[index].get_container());
        }
        // Set the row type.
        if (rowType != null) {
            this._rows[index].set_rowType(rowType);
        }

        // Get the CheckBox on the header.
        var checkBox = $get(String.format($ADC.GridViewCommandColumn.CheckBoxIDFormat, this.get_id(), '-1'));
        if (checkBox) {
            var indexes = this.get_selectedIndexes();
            // Are all rows selected ?
            if (indexes.length == this._rows.length) {
                checkBox.checked = true;
            }
            else if (indexes.length < this._rows.length) {
                checkBox.checked = false;
            }
        }
    },

    _getNamingContainer: function(rowType, index) {
        return this.get_element().id + '$' + rowType.toString() + '$' + index.toString();
    },

    _cleanupRows: function() {
        if (this._rows.length > 0) {
            for (var i = this._rows.length - 1; i > -1; i--) {
                this._rows[i].dispose();
                delete this._rows[i];
            }
        }

        Array.clear(this._rows);
    },

    _canAnimate: function() {
        var canAnimate = this.get_animate();

        if (canAnimate) {
            canAnimate = $ADC.Util.hasAnimationSupport();
        }

        return canAnimate;
    }
}

$ADC.GridView.registerClass('AjaxDataControls.GridView', Sys.UI.Control);

if (typeof (Sys) != 'undefined')
{
	Sys.Application.notifyScriptLoaded();
}